package Ontology;
// TMO ID has to be initialized and filled in AO. 

import java.io.BufferedWriter;
import java.io.FileWriter;
import topindex.DumpToGraphVizWD;
import topindex.HashUtils;
//	import java.util.Hashtable;
//	import java.util.Collection;
//	import java.util.Vector;

import java.util.*;
import wikipedia.kleinberg.*;

public class Slicing 
{

	/**
	 * @param args
	 */
	static private WebDESOOntology WDO;
	static private Object [] oSelClasses, oSelAttributes;
	static private int [] iSelClasses, iSelAttributes;
	static private int iOntoID, iBaseOntoIDTMO;		//	att! all the classes from TMO has to be marked by this Base_Onto_ID
	static private long lStartTime, lEndTime;
	static private Vector vQTop, vQTo, vQFrom, vQComp;
	static public Vector vResClasses, vResAttr, vResHier, vResAssoc, vResClassAttr, vResFunc, vResTextAttrValues;
	static public Vector vAltClasses, vAltFunc;	//	alternative classes and constraints
	static private Hashtable htClasses, htAttributes; 	// for quick search and output only!
	static private Hashtable htForbiddenClasses;		// to spped-up the process of tree traverse. If a top-level class is forbidden then all its children are also forbidden 
	static private Hashtable htDroppedAssoc, htProcessedAssoc; 	// 1st for output only!, 2nd for quick search	2007-01-25
	static private Vector vWDCompHave2BProcessed;	//	a list of compatible constraints containing references to selected classes
	static private int [] iCompatibleClassesID;
	
	static boolean bDebugHier, bDebugAssoc, bDebugAttr;	//	2006-06-28	PMNew
	static private int iCountAssoc = -1;
	
	public static void main( String[] args ) 
	{
		ClassAttr clattrTemp;
		Classes clTempClass;
		Attributes clTempAttr;
		int iTempAttrID, iTempClassID;
		boolean bWasFound;
		Object[] oTemp;
		
		// TODO Auto-generated method stub
		
		bDebugHier = false;
		bDebugAssoc = false;	//	true ; //
		bDebugAttr = false;	//	2006-06-28	PMNew
		
		//	System.out.println( "Begin reading of ontology..." );
		
		lStartTime = System.currentTimeMillis();

		stubVars();
		
		vResClasses = new Vector();
		vResAttr = new Vector();
		vResHier = new Vector();
		vResAssoc = new Vector();
		vResClassAttr = new Vector();
		vResFunc = new Vector();
		vResTextAttrValues = new Vector();
		
		htClasses = new Hashtable();
		htAttributes = new Hashtable();
		htForbiddenClasses = new Hashtable();	//	2007-01-25
		
		htDroppedAssoc = new Hashtable();	//	2007-01-25
		htProcessedAssoc = new Hashtable();	//	2007-01-25
		
		vWDCompHave2BProcessed = new Vector();
		
		vAltClasses = new Vector();
		vAltFunc = new Vector();

		
		//	WDO = new WebDESOOntology( iOntoID );	//	OntoID
		WDO = new WebDESOOntology( iOntoID, 1 );	//	OntoID
		
		System.out.println( "Finish reading of ontology\n" );

		if ( WDO == null ) return;
		if ( isOntologyEmpty() )
		{
			System.out.println( Messages.sForAll[ Messages.iCurrentLanguage ][11] );	// Information about this ontology is absent
			return;
		}
		if ( ! isSelectionCorrect() )
		{
			System.out.println( Messages.sForAll[ Messages.iCurrentLanguage ][12] );	// Internal error: Selected elements are not found in the ontology
			return;
		}
		
		//	Fill vWDCompHave2BProcessed
		WDComp WDCompAux;
		boolean bFirstClass, bSecondClass; // to check situation when two selected classes are incompatible
		int iClass1ID, iClass2ID;			//	to reduce number of calls of methods
		for ( int iComp = 0; iComp < WDO.vWDComp.size(); iComp++ )
		{
			//if (iComp == 355 ) 
			//{
			//	System.out.println( "I am here" );
			//};
			WDCompAux = ( WDComp )WDO.vWDComp.elementAt( iComp );
			bFirstClass = false;
			bSecondClass = false;
			iClass1ID = WDCompAux.getClass1ID();
			iClass2ID = WDCompAux.getClass2ID();
			if (  iClass1ID == iClass2ID )
			{
				System.out.println( "Wrong data in ontology (compatibility between same classes). ID " + WDCompAux.getIDFromDB() );
			}
			else
			{
				for ( int iSel = 0; iSel < iSelClasses.length; iSel++ )
				{
					if ( iClass1ID == iSelClasses[iSel] ) 
					{
						bFirstClass = true;
						if ( WDCompAux.getIsCompatible() == 1 )vWDCompHave2BProcessed.add( new Integer( iClass2ID ) );
					}
					if ( iClass2ID == iSelClasses[iSel] )
					{
						bSecondClass = true;
						if ( WDCompAux.getIsCompatible() == 1 )vWDCompHave2BProcessed.add( new Integer( iClass1ID ) );
					}
					if( bFirstClass || bSecondClass ) iSel = iSelClasses.length + 1;	// stop the loop
				}	//	loop by selected classes
				if( bFirstClass || bSecondClass ) 
				{
					//	vWDCompHave2BProcessed.add( WDCompAux );
					if( bFirstClass && bSecondClass && ( WDCompAux.getIsCompatible() == 0 ) ) System.out.println( "Wrong data in selection (incompatibility between selected classes). ID " + WDCompAux.getIDFromDB() );
					else
					{
						if ( WDCompAux.getIsCompatible() == 0 )		//	fill forbiden classes for incompatible !!! ATT !!! Can be error - double index
						{
							if ( bFirstClass ) htForbiddenClasses.put( new Integer( iClass2ID ), new Integer( iClass2ID ) );
							if ( bSecondClass ) htForbiddenClasses.put( new Integer( iClass1ID ), new Integer( iClass1ID ) );
							//to debug - print!
							//	if ( bFirstClass ) htForbiddenClasses.put( new Integer( htForbiddenClasses.size() ), new Integer( iClass2ID ) );
							//	if ( bSecondClass ) htForbiddenClasses.put( new Integer( htForbiddenClasses.size() ), new Integer( iClass1ID ) );
						}
					}
				}
			}	//	check compatibility
		}
		
		iCompatibleClassesID = new int[ vWDCompHave2BProcessed.size() ];
		for ( int i = 0; i < vWDCompHave2BProcessed.size(); i++ )
		{
			iCompatibleClassesID[ i ] = Integer.parseInt( vWDCompHave2BProcessed.elementAt( i ).toString() );
		}
		vWDCompHave2BProcessed = null;
		
		WDCompAux = null;
		lStartTime = System.currentTimeMillis();
		for ( int i = 0; i < WDO.vClassAttr.size(); i++ )
		{
			clattrTemp = ( ClassAttr )WDO.vClassAttr.elementAt( i );
			iTempAttrID = clattrTemp.getAttrID();
			for ( int j = 0; j < oSelAttributes.length; j++ )
			{
				if ( iSelAttributes[j] == iTempAttrID )
				{
					j = oSelAttributes.length + 1;
					clattrTemp.setIsMarked( true );
					//	WDO.vClassAttr.setElementAt( clattrTemp, i );
				}
			};
		};
		//	System.out.println( "Finish attributes marking in pairs! Time: " +  ( System.currentTimeMillis() - lStartTime ) + "\n" );

		//	Check classes having all the marked attributes OR/AND all the inherited attributes
		lStartTime = System.currentTimeMillis();
		iTempClassID = -1;
		bWasFound = true;
		
		boolean bWasFoundInheritedAttr = false;		//	to check the inherited attributes
		boolean bWasFoundNotInheritedAttr = false;	//	to check the inherited attributes
		
		for ( int i = 0; i < WDO.vClassAttr.size(); i++ )
		{
			clattrTemp = ( ClassAttr )WDO.vClassAttr.elementAt( i );
			if ( ( iTempClassID == clattrTemp.getClassID() )		// class has not been changed
					//	|| ( i == WDO.vClassAttr.size() - 1 ) 
					)
			{
				//	nothing to do
				//	select * from class_attr where attr_id not in (select id from attr )
				//	select * from class_attr where class_id not in (select id from class )
				//	select * from acon where onto_id = 101 and class1_id not in (select id from class )
				//	select * from hierarchy where onto_id = 101 and parent_class_id not in (select id from class )
			}
			else													// class has been changed
			{
				changeClass( iTempClassID, bWasFound, bWasFoundInheritedAttr, bWasFoundNotInheritedAttr, i );
				//	re-init vars again
				iTempClassID = clattrTemp.getClassID();
				bWasFound = false;
				bWasFoundInheritedAttr = false;
				bWasFoundNotInheritedAttr = false;
			};
			
			//	temporary, debug only
			//	if ( iTempClassID == 63218 ) System.out.println( "MATTR: " + clattrTemp );
			//	if ( iTempClassID == 62732 ) System.out.println( clattrTemp.toString() );
				
			if ( !bWasFound ) bWasFound = !clattrTemp.getIsMarked();
			// if ClassID != ParentClassID then the attribute is inherited
			if ( !bWasFoundInheritedAttr ) bWasFoundInheritedAttr = ( clattrTemp.getClassID() != clattrTemp.getFatherClassID() ) ;
			if ( !bWasFoundNotInheritedAttr ) bWasFoundNotInheritedAttr = ( clattrTemp.getClassID() == clattrTemp.getFatherClassID() ) ;
		};
		changeClass( iTempClassID, bWasFound, bWasFoundInheritedAttr, bWasFoundNotInheritedAttr, -1 );	//	the last record
		//	System.out.println( "Finish classes checking (with marked attributes)! Time: " +  ( System.currentTimeMillis() - lStartTime ) + "\n" );

		//	Put flag IsMarked to classes
		for ( int i = 0; i < oSelClasses.length; i++ )
		{
			if ( ! WDO.htClasses.containsKey( oSelClasses[i] ) )
			{
				System.out.println( "Class not found: " + Integer.parseInt( oSelClasses[i].toString() ) );
			}
			else
			{
				clTempClass = ( Classes ) WDO.htClasses.get( oSelClasses[i] );
				clTempClass.setIsMarked( true );
			}
		};

		//	Put flag IsMarked to attributes
		for ( int i = 0; i < oSelAttributes.length; i++ )
		{
			if ( ! WDO.htAttributes.containsKey( oSelAttributes[i] ) )
			{
				System.out.println( "Attribute not found: " + iSelAttributes[i] );
			}
			else
			{
				clTempAttr = ( Attributes ) WDO.htAttributes.get( oSelAttributes[i] );
				clTempAttr.setIsMarked( true );
			}
		};

		markClassWithAttributes();		//	Step 1
		//	printIntermediateData( "Step 1" );
		buildSlice();					//	Step 2 - taxonomy to top
		//	printIntermediateData( "Step 2" );
		addLeaves();					// 	Step 3 - taxonomy to bottom
		synchClassesInSliceAndOnto();					//	Synchronize data for further use
		//	printIntermediateData( "Step 3" );
		
		int iLoopCount;
		iLoopCount = 0;
		while ( isClassesLeft() )
		{
			iLoopCount++;
			addHier();						// 	Step 4
			if ( iLoopCount == 6 ) printIntermediateData( "Step 4, Hierarchy, Step # " + iLoopCount );
			
			synchClassesInSliceAndOnto();					//	Synchronize data for further use
			addAssoc( );						// 	Step 5
			//	addAssoc( 2 );
			if ( iLoopCount == 99 ) bDebugAssoc = true;
			if ( iLoopCount == 99  ) 
			{
					printIntermediateData( "Step 4, Associative, Step # " + iLoopCount );
					System.out.println( "Number of forbidden classes id: " + htForbiddenClasses.size() );
					bDebugAssoc = false;
			}
			//	if ( iLoopCount > 0 ) break;
			//	MakeDump!!!
		}
		
		addFunc();						// 	Step Last
		addAttrs();						// 	Step Last
		
		//	Text attr values. !!! HAS TO BE CHANGED
		for ( int iTAV = 0; iTAV < WDO.vWDTextAttrValues.size(); iTAV++ )
		{
			vResTextAttrValues.add( ( WDTextAttrValues )WDO.vWDTextAttrValues.elementAt( iTAV ));
		};
		
		//	System.out.println( "Total loops: " + iLoopCount );
		//	printIntermediateData( "The final slice" );
		
		//	*********************************
		//	if ( 1 ==2 )
		//	{
			//	the final vectors:
			System.out.println( "================================" );
			if ( ( vResClasses.size() == 0 ) && ( vResAttr.size() == 0 ) )
			{
				System.out.println( "The final slice is empty." );
			}
			else
			{
				System.out.println( "The final slice:" );
				System.out.println( "================" );
				if ( vResClasses.size() > 0 ) System.out.println( "CLASSES:" ); 
				for ( int i = 0; i < vResClasses.size(); i ++ )
				{
					System.out.println( "" + ( i + 1 ) + " " + ( Classes ) vResClasses.elementAt( i ) );
					
					// 	temporarty code
					//	System.out.println( "FROM CLASS" +  ( Classes ) WDO.htClasses.get( new Integer( ( ( Classes ) vResClasses.elementAt( i ) ).getClassID() ) ) );
				};
				
				
				//	DEL IT
				int iCountAssoc, iCountAssocInher;
				iCountAssoc = 0;
				iCountAssocInher = 0;
				for ( int ii = 0; ii < WDO.vWDAssoc.size(); ii++ )
				{
					if ( ( ( WDAssoc ) WDO.vWDAssoc.elementAt( ii ) ).getIsInherited() ) iCountAssocInher++;
					else iCountAssoc++; 
				}
				
				System.out.println( "\nFOUND ASSOCIATIVE RELATIONS. " + WDO.vWDAssoc.size() + "//"+ 
						iCountAssoc + "//" + iCountAssocInher );
			}	//	print the result
			
			htClasses.put( new Integer( 0 ), new Classes( 0, "Top_of_the_Slice", -1, false, "Instead of thing", "Thing", "Top level class", 0 ) );	//	add root
			
			System.out.println( "\n================================" );
			System.out.println( "Some statistics:" );
			System.out.println( "   Total classes: " + vResClasses.size() );
			System.out.println( "   Total attributes: " + vResAttr.size() );
			
			int iAuxCount;
	
			iAuxCount = 0;
			for ( int ii = 0; ii < vResAssoc.size(); ii++ ) if ( !( ( WDAssoc ) vResAssoc.elementAt( ii ) ).getIsInherited() ) iAuxCount++;
			System.out.println( "   Total associative constraints: " + iAuxCount );
			
			iAuxCount = 0;
			for ( int ii = 0; ii < vResAssoc.size(); ii++ ) iAuxCount++;
			System.out.println( "   Total associative constraints with inherited: " + iAuxCount );
	
			iAuxCount = 0;
			for ( int ii = 0; ii < vResHier.size(); ii++ ) if ( !( ( WDHier ) vResHier.elementAt( ii ) ).getIsInherited() ) iAuxCount++;
			System.out.println( "   Total hierarchical constraints: " + iAuxCount );
	
			//	Classes clTemp = ( Classes )htClasses.get( new Integer ( 63071 ) );
			//	htClasses.remove( new Integer ( 63071 ) );
			//	htClasses.putAll()
			

		if ( 1 ==2 )		//	dump to file
		{
			Map<String, Classes>  class_name2object = HashUtils.createMapClassNameToObject( htClasses );
			DumpToGraphViz dump;
			dump = new DumpToGraphViz();
	        if (  dump != null) 
	        {
	            dump.file_dot.SetDir("C:/MYWORK/SPIIRAS/SOFT/graphviz/");
	            
	            dump.file_bat.SetDir("C:/MYWORK/SPIIRAS/SOFT/graphviz/");
	            dump.file_bat.SetFilename("e.bat");
	            dump.file_bat.Open(true, "Cp866");
	            
	            dump.file_sh.SetDir("C:/MYWORK/SPIIRAS/SOFT/graphviz/");
	            dump.file_sh.SetFilename("e.sh");
	            dump.file_sh.Open(true, "Cp1251");
	
	        	dump.DotOpen("aaa.dot");
	            DumpToGraphVizWD.dumpClasses(
	            		class_name2object, 
	            		htClasses,
	            		dump);
	            dump.BatEnd();
	        }
	        
	        saveSliceToFile();
	        
		};	// 1==2
		
	}
	
	/**
	 * Change 1-3 attributes of the class
	 * 
	 * @param iiTempClassID - Class ID
	 * @param ibWasFound - if this parameter is false then all attributes of the class are Marked
	 * @param ibWasFoundInheritedAttr - the indicator that the class has inrited attributes
	 * @param ibWasFoundNotInheritedAttr - the indicator that all attributes of the class are inherited
	 * @param iiLoopCount
	 */
	private static void changeClass( int iiTempClassID, boolean ibWasFound, boolean ibWasFoundInheritedAttr, boolean ibWasFoundNotInheritedAttr, int iiLoopCount )
	{
		if ( iiTempClassID == -1 ) return;
		
		//	if ( iiTempClassID == 63218 ) System.out.println( "Change class 63218. Not all marked: " + ibWasFound + " Has inherited attrs: " + ibWasFoundInheritedAttr + " Has own attrs:" + ibWasFoundNotInheritedAttr );
		
		Classes clTemp;
		
		//	if all the marked - change a class in hashtable
		if ( !ibWasFound ) System.out.println( "Class with all marked attributes. ClassID: " + iiTempClassID + " i: " + iiLoopCount  );	//	+ " ClassAttr: " +  clattrTemp
		
		if ( ! WDO.htClasses.containsKey( new Integer( iiTempClassID ) ) )
		{
			System.out.println( "Class with all marked OR/AND inherited attributes. Class not found: " + iiTempClassID );
		}
		else
		{
			clTemp = ( Classes ) WDO.htClasses.get( new Integer( iiTempClassID ) );
			
			if ( !ibWasFound )clTemp.setIsAllAttrMarked( true );					//	All the attributes are marked
			if ( ibWasFoundInheritedAttr ) clTemp.setHasInheritedAttr( true );		// the class has inherited attribute(s)
			if ( !ibWasFoundNotInheritedAttr ) clTemp.setAllAttrInherited( true );	// all the attributes of the class are inherited
		}
		//	}
		return;
	}

	private static boolean isOntologyEmpty( ) 
	{
		if ( ( WDO.htClasses.size() == 0 ) && ( WDO.htAttributes.size() == 0 ) ) return true;
		return false;
	}
	
	private static boolean isSelectionCorrect( ) 	//	the function is for debuging purposes only
	{
		for ( int i = 0; i < oSelClasses.length; i++ )
		{
			if ( ! WDO.htClasses.containsKey( oSelClasses[i] ) )
			{
				System.out.println( "Class not found: " + Integer.parseInt( oSelClasses[i].toString() ) );
				return false;
			}
		};

		for ( int i = 0; i < oSelAttributes.length; i++ )
		{
			if ( ! WDO.htAttributes.containsKey( oSelAttributes[i] ) )
			{
				System.out.println( "Attribut not found: " + Integer.parseInt( oSelAttributes[i].toString() ) );
				return false;
			}
		};

		return true;
	}

	private static void stubVars( ) 
	{
		Messages.InitializeCommon();
		Messages.InitializeForAll();

		//	select * from class, term where onto_id = 100 and term_id = term.id and text like "App / DB%"
		//	select * from class, term where class.id = 62528 and term_id = term.id 
		//	iOntoID = 101;
		iOntoID = 139;
		iBaseOntoIDTMO = 133;
		
		iSelClasses =  new int [1];
		//	iSelClasses[0] = 84300;			// event manager
		iSelClasses[0] = 84197;			// fire
		//	iSelClasses[0] = 84212;			// Air transportation
		
		//	iSelClasses[1] = 84732;
		
		//	Ontology 101 (Magnus)
		//	iSelClasses[0] = 63220;	//	assembler
		//	iSelClasses[0] = 63218;	//	product planner
		//	iSelClasses[1] = 63478;	//	product planner
		//	iSelClasses[0] = 63219;	//	purchaser
		//	iSelClasses[0] = 63221;	//	distributor
		
		iSelAttributes =  new int [0];
		//	iSelAttributes =  new int [2];
		//	iSelAttributes[0] = 40206;
		//	iSelAttributes[1] = 40224;
		
		/*
		iSelClasses =  new int [5];
		iSelClasses[0] = 62528;	//	Deploy Local Sales App / DB Server in Paris ->(ass) App/DB Server
		iSelClasses[1] = 62530;	//	Data quality issues	->(ass) Procure top-of-the-line market reporting support
		iSelClasses[2] = 62520;	//	Common system for parametric bike design -> (ass) PARMDES New design tool
		iSelClasses[3] = 62732;	//	France
		//	iSelClasses[3] = 62890;		//	Paris
		iSelClasses[4] = 62576;			//	Europe
		//	iSelClasses[5] = 62479;			//	Business operation. Terrible results on the step 3

		iSelAttributes =  new int [19];
		//	62515	Component quality recording (barcoded) -> (ass) Ensure data quality in WW reporting
		iSelAttributes[0] = 30800;
		iSelAttributes[1] = 30801;
		iSelAttributes[2] = 30802;
		iSelAttributes[3] = 30803;
		iSelAttributes[4] = 30804;
		iSelAttributes[5] = 30799;
		iSelAttributes[6] = 30798;
		
		//	62514, not all	Find a better design tool ->(ass) Common system for parametric bike design
		iSelAttributes[7] = 29385;
		iSelAttributes[8] = 29386;
		iSelAttributes[9] = 29387;
		iSelAttributes[10] = 29388;
		iSelAttributes[11] = 29389;
		
		//	Attributes of the class 62520 (see above)
		iSelAttributes[12] = 30676;
		iSelAttributes[13] = 30677;
		iSelAttributes[14] = 30678;
		iSelAttributes[15] = 30679;
		iSelAttributes[16] = 30680;
		iSelAttributes[17] = 30681;
		iSelAttributes[18] = 30682;
		*/

		if ( iSelClasses.length == 0 ) oSelClasses = new Object [0];  
		else
		{
			oSelClasses =  new Object [ iSelClasses.length ];
			for (int i = 0; i< iSelClasses.length; i++ )
			{
				oSelClasses[i] = new Integer ( iSelClasses[i] ) ;
			}
		}
		
		if ( ( iSelAttributes.length == 0 ) ) oSelAttributes = new Object [0];  
		else
		{
			oSelAttributes = new Object [ iSelAttributes.length ];
			for (int i = 0; i< iSelAttributes.length; i++ )
			{
				oSelAttributes[i] = new Integer ( iSelAttributes[i] ) ;
			}
		}
		
		Messages.iCurrentLanguage = 1;	//	Language
		return;
	}
	
	//	********************************************************************************
	
	private static void markClassWithAttributes()
	{
		/**
		 * The first step of the algorithm:
		 * looks for classes which are not marked but all the attributes are marked. Makr out the lowest class
		 * covered the attributes
		 * Divided to the following steps:
		 * 
		 * 1) work with leaves. If a leaf is not marked, contains all the marked attributes and attributes belong to leaf - mark out the leaf
		 * 2)  
		 */
		Classes clTemp;
		
		//	Step 1: traverse the leaves
		for (int i = 0; i< WDO.vClasses.size(); i++ )
		{
			clTemp = getClassAtPosition( i, "markClassWithAttributes" );
			
			if ( clTemp != null )
			{
				//	class is a leaf
				if ( clTemp.getIsLeaf() )
				{
					//	class contains attribute(s)
					if ( clTemp.getPosInClassAttr() > 0 )
					{
						//	----------------	get Class ID, position in class-attribute and change isAllAttribute Marked (if necessary)
						//	All the attributes are not inherited and marked
						//	The class is not marked
						if ( clTemp.getIsAllAttrMarked() && !clTemp.getHasInheritedAttr() && !clTemp.getIsMarked() )		// all the attributes are marked
						{
							clTemp.setIsMarked( true );
							System.out.println( "Class was not marked, all the attributes are not inherited and marked: " +  clTemp );
						}
					}	//	class contains attribute(s)
				}		//	class is a leaf
			}			//  class is not null
		}				//	LOOP
		return;
	}
	
	private static void buildSlice()	// see statechart diagram for details 
	{
		int iFatherID;
		Classes clTemp;
		
		iFatherID = 0;
		clTemp = null;
		
		vQTop = new Vector();
		
		//	ClTemp should be used for IsInsert modification!
		
		//	Search for the thing
		for (int i = 0; i < WDO.vClasses.size(); i++ )
		{
			clTemp = getClassAtPosition( i, "markClassWithAttributes" );
			
			if ( clTemp != null )
			{
				if ( clTemp.getParentID() == iFatherID )	//	0 - THING
				{
					
					getClassChildren( clTemp.getClassID(), i, 1, false );
					i = WDO.vClasses.size() + 1;
				}
			
			}			// class is not null
		}				//	LOOP
		while ( vQTop.size() > 0 )
		{
			//	System.out.println( "removeElementAt" );
			clTemp = null;
			clTemp = ( Classes )vQTop.elementAt( 0 );
			if ( clTemp.getIsMarked() )		//
			{
				//	FindParent
				findParent( clTemp );
				//	Find IS-A
				findIsA( clTemp );
				// IsInserted
				Object oCurClassID;	//	to find in HashTable
				oCurClassID = new Integer( clTemp.getClassID() );
				clTemp = null;
				clTemp = getClassByKey( oCurClassID, "build Slice, mark class as inserted" );
				if ( clTemp != null ) clTemp.setIsInserted( true );
				clTemp = null;
			}
			else
			{
				getClassChildren( clTemp.getClassID(), 0, 1, false );
			}
			
			vQTop.removeElementAt( 0 );
		}
		return;
	}
	
	//	the common method for all the classes
	private static Classes getClassAtPosition( int iiLoopCount, String isMessage ) 
	{
		Object oTemp;
		Classes clTemp;
		
		oTemp = WDO.vClasses.elementAt( iiLoopCount );
		//	return getClassByKey( oTemp, isMessage );
		if ( ! WDO.htClasses.containsKey( oTemp ) )
		{
			System.out.println( "Class not found " + isMessage + ": " + oTemp.toString() );
			return null;
		}
		else
		{
			return ( Classes ) WDO.htClasses.get( oTemp );
		}
	}
	
	private static Classes getClassByKey( Object ioKeyValue, String isMessage ) 
	{
		Classes clTemp;
		
		if ( ! WDO.htClasses.containsKey( ioKeyValue ) )
		{
			System.out.println( "Class not found " + isMessage + ": " + ioKeyValue.toString() );
			return null;
		}
		else
		{
			return ( Classes ) WDO.htClasses.get( ioKeyValue );
		}
	}
	
	//	the common method for all the classes
	//	bCheckCompatibility affects only if iivQTopQToQFrom == 3
	private static void getClassChildren( int iiParentID, int iiElementToSkip, int iivQTopQToQFrom, boolean bCheckCompatibility )
	{
		Classes clTemp, clTempForBid;
		clTemp = null;
		boolean bDoIt = true;
		Vector vChildrenClasses;
		
		vChildrenClasses = new Vector();
		
		for (int i = 0; i < WDO.vClasses.size(); i++ )
		{
			if ( i != iiElementToSkip )
			{
				clTemp = getClassAtPosition( i, "get ClassChildren" );
				
				if ( clTemp != null )
				{
					if ( clTemp.getParentID() == iiParentID )
					{
						switch ( iivQTopQToQFrom )
						{
							case 1: 
							{
								vQTop.add( clTemp );
								break;
							}
							case 2: 
							{
								vQTo.add( clTemp );
								break;
							}
							case 3: 
							{
								if ( bCheckCompatibility )
								{
									//	if ( htForbiddenClasses.containsKey( new Integer( clTemp.getClassID() ) ) ) System.out.println( "getClassChildren - forbidden class " + clTemp.getClassID() );
									//	else vChildrenClasses.add( clTemp );
									
									if ( !htForbiddenClasses.containsKey( new Integer( clTemp.getClassID() ) ) ) vChildrenClasses.add( clTemp );
								}
								else vQFrom.add( clTemp );
								break;
							}
							case 4: 
							{
								vQComp.add( clTemp );
								break;
							}
						}	//	end switch
					}
				}			//	Class is not null
				
			}				//	not skipped element
			
		}				//	LOOP
		
		if ( bCheckCompatibility && vChildrenClasses.size() > 0 )		// check compatibility
		{
			boolean bIsIncompatible[ ] = new boolean [vChildrenClasses.size()];
			for( int i = 0; i < bIsIncompatible.length ; i++ ) bIsIncompatible[ i ] = false;
			int iCurClassID;
			for( int i = 0; i < vChildrenClasses.size(); i++ )
			{
				iCurClassID = ( ( Classes )vChildrenClasses.elementAt( i ) ).getClassID();
				
				if ( iCurClassID == 84220 )
				{
					System.out.println( "Charitable Donation!!!" );
				}
				
				if ( htClasses.containsKey(  new Integer( iCurClassID ) ) )	// check if a class is already included into slice 
				{
					bIsIncompatible[ i ] = true;
				}
				else
				{
					for( int j = 0; j < iCompatibleClassesID.length; j++ )
					{
						if ( iCurClassID == iCompatibleClassesID[j])
						{
							/*
							//	System.out.println( "Shit happend!" + iCurClassID );
							if ( iCurClassID == 84218 )
							{
								System.out.println( "aaa" );
							}
							*/
								
							j = iCompatibleClassesID.length + 1;
							bIsIncompatible[ i ] = true;
							bDoIt = false;
						}
					}
				}	//	class is not in the slice
			}
			if ( bDoIt )
			{
				for( int i = 0; i < vChildrenClasses.size(); i++ )
				{
					vQFrom.add( vChildrenClasses.elementAt( i ) );
				}
			}
			else
			{
				for( int i = 0; i < bIsIncompatible.length ; i++ )
				{
					if ( bIsIncompatible[i] ) vQFrom.add( vChildrenClasses.elementAt( i ) );
					else
					{
						// remove! put into incompatible!
						markClassBranchAsForbidden( ( ( Classes) vChildrenClasses.elementAt( i ) ).getClassID() );
					}
				}
			}
		}
		
		return;
	}

	/**
	 * 
	 * @param iiParentID
	 * @param iiFlagOfAction - set to vResClasses a flag: 1 - HiewProc, 2 - AssocProc
	 */
	private static void getClassChildrenInSlice( int iiParentID, int iiFlagOfAction )
	{
		Classes clTemp;
		for (int i = 0; i < vResClasses.size(); i++ )
		{
			clTemp = new Classes( ( Classes ) vResClasses.elementAt( i ) );
			
			if ( clTemp.getParentID() == iiParentID )
			{
				vQTop.add( clTemp );
				clTemp = null; 
				switch ( iiFlagOfAction )
				{
					case 1:
					{
						( ( Classes ) vResClasses.elementAt( i ) ).setIsHierProc( true );
						break;
					}
					case 2:
					{
						( ( Classes ) vResClasses.elementAt( i ) ).setIsAssocProc( true );
						break;
					}
					case -1:
					{
						( ( Classes ) vResClasses.elementAt( i ) ).setIsAssocProc( true );
						break;
					}
					case -2:
					{
						( ( Classes ) vResClasses.elementAt( i ) ).setIsAssocProcInh( true );
						break;
					}
					case -3:
					{
						( ( Classes ) vResClasses.elementAt( i ) ).setIsAssocProc( true );
						( ( Classes ) vResClasses.elementAt( i ) ).setIsAssocProcInh( true );
						break;
					}
				}
			}
		}				//	LOOP
		
	}

	//	the auxiliary method for buildSlice
	private static int findParent( Classes iclCurrentClass )
	{
		int iParentID, iClassID; 	//	, iQuantOfAttrsChild, iQuantOfAttrsParent;
		Object oTemp;
		Classes clTemp, clTempChild, clNewClass;
		
		//	iQuantOfAttrsChild = 0;
		//	iQuantOfAttrsParent = 0;
		
		//	first find the reference in has table to change data
		//	clTemp = iclCurrentClass;
		clTemp = ( Classes ) WDO.htClasses.get( new Integer( iclCurrentClass.getClassID() ) );
		clTempChild = ( Classes ) WDO.htClasses.get( new Integer( iclCurrentClass.getClassID() ) );
		if ( clTemp == null )
		{
			System.out.println( "Class not found: " + "Find In HashTable, ClassID " + iclCurrentClass.getClassID() );
			return -1;
		}
			
		
		//	2007-01-16 - NOT ALL ATTRIBUTES ARE INHERITED!!! Take them all!
		if ( !iclCurrentClass.getHasInheritedAttr())
		{
			//	add a relation from thing to the class
			clNewClass = new Classes( clTemp.getClassID(), clTemp.getClassName(), 0, clTemp.getIsLeaf(), clTemp.getClassDescr(), clTemp.getStemClassName(), clTemp.getStemClassDescr(), clTemp.getBaseOntoID() );
			vResClasses.add( clNewClass );
			htClasses.put( new Integer( clNewClass.getClassID() ), clNewClass );
			
			iclCurrentClass.setIsInserted( true );
			iclCurrentClass.setIsMarked( true );
		}
		else
		{
			//	iQuantOfAttrsChild = calcQuantOfAttrs( clTemp.getClassID() );
			//	Take father
			//	compare number of attributes
			//	if they are equal - take the next fater. else - add relation and father
			boolean bContSearchFather = true;
			while ( bContSearchFather ) //	( iclCurrentClass.getHasInheritedAttr() )
			{
				iParentID = clTemp.getParentID();
				iClassID = clTemp.getClassID();
				oTemp = new Integer( iParentID );
				
				clTemp = null;
				//	iclCurrentClass = getClassByKey( oTemp, "Find Parent, ClassID " + iClassID + " ParentID " + iParentID );
				
				if ( ! WDO.htClasses.containsKey(  oTemp ) )
				{
					System.out.println( "Class not found: " + "Find Parent, ClassID " + iClassID + " ParentID " + iParentID );
					return -1;
				}
				clTemp = ( Classes ) WDO.htClasses.get( oTemp );
				if ( !clTemp.getAllAttrInherited() )		// not all attributes are inherited
				{
					clNewClass = new Classes( 
							clTempChild.getClassID(), 
							clTempChild.getClassName(), 
							clTemp.getClassID(), 
							clTempChild.getIsLeaf(), 
							clTempChild.getClassDescr(), 
							clTempChild.getStemClassName(), 
							clTempChild.getStemClassDescr(), 
							clTempChild.getBaseOntoID() );
					vResClasses.add( clNewClass );
					htClasses.put( new Integer( clNewClass.getClassID() ), clNewClass );
					
					clTempChild.setIsInserted( true );
					clTempChild.setIsMarked( true );
					
					clTempChild = null;
					clTempChild = ( Classes ) WDO.htClasses.get( oTemp );
					
					bContSearchFather = clTemp.getHasInheritedAttr() || clTemp.getIsInserted();
				}
				
				
			};	//	while
			//	ADD THE ROOT CLASS!!!
			if ( !clTempChild.getIsInserted() )
			{
				//	add a relation from thing to the last found class
				clNewClass = new Classes( 
						clTempChild.getClassID(), 
						clTempChild.getClassName(), 
						0, 
						clTempChild.getIsLeaf(), 
						clTempChild.getClassDescr(), 
						clTempChild.getStemClassName(), 
						clTempChild.getStemClassDescr(), 
						clTempChild.getBaseOntoID() );
				vResClasses.add( clNewClass );
				htClasses.put( new Integer( clNewClass.getClassID() ), clNewClass );
				
				clTempChild.setIsInserted( true );
				clTempChild.setIsMarked( true );
				
			};	//	class is not inserted yet
		}		//	how class should be added
		
		/*
		//	If all the attributes are inherited
		// 	change input parameter - reference to father ID
		//	mark out father
		//	add an IS-A relation with marked to input parameter 	
		
		//	while ( iclCurrentClass.getAllAttrInherited() )	//	2007-01-16
		while ( iclCurrentClass.getHasInheritedAttr() )		//	2007-01-16
		{
			
			iParentID = iclCurrentClass.getParentID();
			iClassID = iclCurrentClass.getClassID();
			oTemp = new Integer( iParentID );
			
			iclCurrentClass = null;
			//	iclCurrentClass = getClassByKey( oTemp, "Find Parent, ClassID " + iClassID + " ParentID " + iParentID );
			
			if ( ! WDO.htClasses.containsKey(  oTemp ) )
			{
				System.out.println( "Class not found: " + "Find Parent, ClassID " + iClassID + " ParentID " + iParentID );
				return -1;
			}
			else
			{
				iclCurrentClass = ( Classes ) WDO.htClasses.get( oTemp );
			}
		}
		
		if ( ( clTemp.getClassID() == iclCurrentClass.getClassID()) )
		{
			//	add a relation from thing to the class
			clNewClass = new Classes( clTemp.getClassID(), clTemp.getClassName(), 0, clTemp.getIsLeaf(), clTemp.getClassDescr(), clTemp.getStemClassName(), clTemp.getStemClassDescr(), clTemp.getBaseOntoID() );
			vResClasses.add( clNewClass );
			htClasses.put( new Integer( clNewClass.getClassID() ), clNewClass );
			
			iclCurrentClass.setIsInserted( true );
			iclCurrentClass.setIsMarked( true );
		}
		else
		{
			if ( !iclCurrentClass.getIsInserted() )		//	should be inserted and marked
			{
				clNewClass = new Classes( iclCurrentClass.getClassID(), iclCurrentClass.getClassName(), 0, iclCurrentClass.getIsLeaf(), iclCurrentClass.getClassDescr(), iclCurrentClass.getStemClassName(), iclCurrentClass.getStemClassDescr(), iclCurrentClass.getBaseOntoID() );
				vResClasses.add( clNewClass );
				htClasses.put( new Integer( clNewClass.getClassID() ), clNewClass );

				iclCurrentClass.setIsInserted( true );	// data in hash table is changed
				iclCurrentClass.setIsMarked( true );
			}
			clNewClass = new Classes( clTemp.getClassID(), clTemp.getClassName(), iclCurrentClass.getClassID(), clTemp.getIsLeaf(), clTemp.getClassDescr(), clTemp.getStemClassName(), clTemp.getStemClassDescr(), clTemp.getBaseOntoID() );
			vResClasses.add( clNewClass );
			htClasses.put( new Integer( clNewClass.getClassID() ), clNewClass );

			clTemp.setIsMarked( true );
			clTemp.setIsInserted( true );
		}
		*/
		
		return 0;
	};

	private static void findIsA( Classes iclCurrentClass )
	{
		Classes clCurClass, clCurSubClass, clNewClass;
		
		vQFrom = new Vector(); 
		vQTo = new Vector();
		
		vQTo.add( iclCurrentClass );
		
		while ( vQTo.size() > 0 )
		{
			clCurClass = ( Classes ) vQTo.elementAt( 0 );
			vQTo.removeElementAt( 0 );
			vQFrom = null;
			vQFrom = new Vector();
			
			getClassChildren( clCurClass.getClassID(), 0, 3, false );
			while ( vQFrom.size() > 0 )
			{
				clCurSubClass = ( Classes ) vQFrom.elementAt( 0 );
				if ( clCurSubClass.getIsMarked() )
				{
					// it is not necessary to change hash table 			FALSE!!!
					clNewClass = new Classes( clCurSubClass.getClassID(), clCurSubClass.getClassName(), clCurClass.getClassID(), clCurSubClass.getIsLeaf(), clCurSubClass.getClassDescr(), clCurSubClass.getStemClassName(), clCurSubClass.getStemClassDescr(), clCurSubClass.getBaseOntoID() );
					vResClasses.add( clNewClass );
					htClasses.put( new Integer( clNewClass.getClassID() ), clNewClass );
					
					clCurClass = ( Classes ) WDO.htClasses.get( new Integer( clCurSubClass.getClassID() ) );
					if ( clCurClass == null )
					{
						System.out.println( "Class not found: " + "Find InHashTable1, ClassID " + clCurSubClass.getClassID() );
						//	return -1;
					}
					else
					{
						clCurClass.setIsInserted( true );
						clCurClass.setIsMarked( true );		//	REDUDANT
					}
					
					vQTo.add( clCurSubClass );
				}
				else
				{
					getClassChildren( clCurSubClass.getClassID(), 0, 3, false );
				}
				vQFrom.removeElementAt( 0 );
			}
		}
		return;
	};
	
	private static void addLeaves()		//	Step 3
	{
		int iSaveVResClassesSize, iCurClassID;
		boolean bHasChild;
		Classes clCurClass, clNewClass, clTemp;
		boolean bDebug;
		
		bDebug = true;
		
		iSaveVResClassesSize = vResClasses.size();
		
		for ( int i = 0; i < iSaveVResClassesSize; i++ )
		{
			bHasChild = false;
			iCurClassID = ( ( Classes ) vResClasses.elementAt( i ) ).getClassID();
			
			for ( int j = 0; j < iSaveVResClassesSize; j++ )
			{
				if ( iCurClassID ==  ( ( Classes ) vResClasses.elementAt( j ) ).getParentID() )
				{
					bHasChild = true;
					j = iSaveVResClassesSize + 1;	//	finish the loop
				}
			}
			
			if ( !bHasChild )
			{
				clCurClass = getClassByKey( new Integer ( iCurClassID ), "addLeafs" );
				if ( clCurClass  != null )
				{
					if ( !clCurClass.getIsLeaf() )
					{
						vQFrom = null;
						vQFrom = new Vector();
						getClassChildren( iCurClassID, 0, 3, false );
						while ( vQFrom.size() > 0 )
						{
							clCurClass = ( Classes ) vQFrom.elementAt( 0 );
							vQFrom.removeElementAt( 0 );
							if ( clCurClass.getIsLeaf() )
							{
								//	add it
								clNewClass = new Classes( clCurClass.getClassID(), clCurClass.getClassName(), iCurClassID, true, clCurClass.getClassDescr(), clCurClass.getStemClassName(), clCurClass.getStemClassDescr(), clCurClass.getBaseOntoID() );
								vResClasses.add( clNewClass );
								htClasses.put( new Integer( clNewClass.getClassID() ), clNewClass );
								
								clTemp = ( Classes ) WDO.htClasses.get( new Integer( clCurClass.getClassID() ) );
								if ( clTemp == null )
								{
									System.out.println( "Class not found: " + "Find InHashTable1, ClassID " + clCurClass.getClassID() );
									//	return -1;
								}
								else
								{
									clTemp.setIsInserted( true );
									clTemp.setIsMarked( true );
								}
							}
							else
							{
								getClassChildren( clCurClass.getClassID(), 0, 3, false );
							}
						}
					}	//	Class is not leaf
				}		//	Class has been found in hash table
			}			//	the class does not have any child
		}
		return;
	}

	private static void addHier()		//	Step 4
	{
		//	ATT! QFrom is used in sub-procedure!!!
		//	System.out.println( "Step 4 is starting..." );

		int iClass1ID, iLoopCount, iParentID;;
		Classes clTemp;
		WDHier wdhTemp;
		
		clTemp = null;
		
		vQTop = null;
		vQTop = new Vector();
		
		iLoopCount = 0;
		
		//	Search for top-level classes
		getClassChildrenInSlice( 0, 1 );
		
		while ( vQTop.size() > 0 )
		{
			iLoopCount++;
			clTemp = ( Classes ) vQTop.elementAt( 0 ) ;
			vQTop.removeElementAt( 0 );
			iClass1ID = clTemp.getClassID();
			iParentID = clTemp.getParentID();
			
			if ( !clTemp.getIsHierProc() )
			{
				for ( int i = 0; i < WDO.vWDHier.size(); i++ )	//	search for hierarchical relations
				{
					wdhTemp = ( WDHier )WDO.vWDHier.elementAt( i );
					if ( wdhTemp.getClass1ID() == iClass1ID )
					{
						addPartOf( wdhTemp, iParentID );
					}
				}
			}	//	Hierarchical relations are not still precessed
			
			getClassChildrenInSlice( iClass1ID, 1 );
		}
		System.out.println( "Step 4 has been finished. Total classes: " + iLoopCount );
	}
	
	//	private static void addPartOf( int iiClass1ID, int iiClass2ID, boolean ibIsInherited )
	private static void addPartOf( WDHier iwdhPartOf, int iiParentID )
	{
		int iClass1ID, iClass2ID, iTaxonomyParentID, iHierarchyParentID, iClass1IDAux;
		boolean bClass2Found, bIsInherited, bCont, bFoundParentHierarchy; 
		Classes clTemp;
		WDHier wdhAux;
		
		iClass1ID =  iwdhPartOf.getClass1ID();
		iClass2ID =  iwdhPartOf.getClass2ID();
		bClass2Found = htClasses.containsKey( new Integer( iClass2ID ) );  
		bIsInherited =  iwdhPartOf.getIsInherited();
		iTaxonomyParentID = 0;
		iHierarchyParentID = 0;

		//	Case 1: Is not inherited and HierClass exists
		if ( !bIsInherited && bClass2Found ) 
		{
			vResHier.add( iwdhPartOf );
			if ( bDebugHier ) System.out.println( iwdhPartOf );	//	2006-06-28	PMNew
			return;
		}

		//	Case 2: Is not inherited and HierClass does not exist
		if ( !bIsInherited && !bClass2Found ) 
		{
			//	follow to the algorithm
			if ( insertClass( iClass2ID, false ) )
			{
				vResHier.add( iwdhPartOf );
				if ( bDebugHier ) System.out.println( "H: Case 2: Class " + iClass2ID );	//	2006-06-28	PMNew
				if ( bDebugHier ) System.out.println( "H: Case 2: Rel " + iwdhPartOf );		//	2006-06-28	PMNew
				return;
			};
			return;
		}

		//	Case 3: Is inherited and HierClass exists
		if ( bIsInherited && bClass2Found ) 
		{
			//	Check parent of the left class.
			boolean bFoundHier;
			bFoundHier = false;
			for ( int i = 0 ; i < vResHier.size(); i++ )
			{
				WDHier wdhTemp;
				wdhTemp = ( WDHier ) vResHier.elementAt( i ); 
				if ( ( wdhTemp.getClass1ID() == iiParentID  ) && ( wdhTemp.getClass2ID() == iClass2ID ) )
				{
					bFoundHier = true;
					i = vResHier.size() + 1;
				}
			}
			if ( bFoundHier )
			{
				// add as-is
				vResHier.add( iwdhPartOf );
				if ( bDebugHier ) System.out.println( "H:Inh&Cl2-AS-IS " + iwdhPartOf );	//	2006-06-28	PMNew
			}
			else
			{
				// add as the first hierarchy
				iwdhPartOf.setIsNotInherited();
				vResHier.add( iwdhPartOf );
				if ( bDebugHier ) System.out.println( "H:Inh&Cl2-NEW " + iwdhPartOf );		//	2006-06-28	PMNew
			}
			return;
		}

		//	Case 4: Is inherited and HierClass does not exist
		if ( bIsInherited && !bClass2Found ) 
		{
			
			//	Search TaxonomyParent
			clTemp = ( Classes )WDO.htClasses.get( new Integer( iClass2ID ) );
			bCont = true;
			while ( bCont )
			{
				if ( clTemp == null )
				{
					//	Say something
					// Impossible situation
					System.out.println( "Wrong Hier1: " + iwdhPartOf );
					bCont = false;
					return;
				}
				if ( clTemp.getAllAttrInherited() )
				{
					//	TaxonomyParent should be found
					clTemp = ( Classes )WDO.htClasses.get( new Integer( clTemp.getParentID() ) );
				}
				else
				{
					bCont = false;
					iTaxonomyParentID = clTemp.getClassID();
				};
			}	//	End: search for TaxonomyParent

			if ( !clTemp.getIsInserted() )	// TaxonomyParent has to be inserted	
			{
				if ( insertClass( iTaxonomyParentID, false ) )
				{
					if ( bDebugHier ) System.out.println( "H: AddTaxPar: " + clTemp );		//	2006-06-28	PMNew
					clTemp.setIsInserted( true );	//	it contains the same reference as htClasses => will be changed
				}
				else
				{
					System.out.println( "Error: H: AddTaxPar: " + clTemp );
					return;
				}
				 	
			};								// TaxonomyParent has to be inserted END

			//	2007-01-17. We will not search for HierarchyParent. This class is HierarchyParent
			clTemp = ( Classes )WDO.htClasses.get( new Integer( iClass1ID ) );
			
			if ( iTaxonomyParentID != iClass2ID )	// HierarchyClass has to be inserted	
			{
				if ( insertClass( iClass2ID, false ) )
				{
					if ( bDebugHier ) System.out.println( "H: AddHierClass: ID2: " + iClass2ID );	//	2006-06-28	PMNew
					
					//	Change IsInserted:
					clTemp = ( Classes )WDO.htClasses.get( new Integer( iClass2ID ) );
					if ( clTemp != null ) clTemp.setIsInserted( true );
					else System.out.println( "Change Inserted error: ID2: " + iClass2ID );
				}
				else
				{
					System.out.println( "Error: H: AddHierClass: ID2: " + iClass2ID );
					return;
				}
				 	
			};								// HierarchyClass has to be inserted END

			iwdhPartOf.setIsNotInherited();	//	NEW! 2007-01-17
			vResHier.add( iwdhPartOf );
			if ( bDebugHier ) System.out.println( "H:Inh&!Cl2-AS-IS " + iwdhPartOf );	//	2006-06-28	PMNew	
			//	Check if iTaxonomyParentID != iClass2ID 
		}

		return;
	}
	
	// insert class into slice
	// 1) no superclass - add to Thing, 
	//	make step 3
	//	
	// 2) superclass exists. make IS-A relation. modify relation between descendant and superclasses
	//	--NO! 2.1) no common descendant - , make step 3. TO THINK - is it possible
	//	--IN 2)! 2.2) modify relation between descendant and superclasses
	private static boolean insertClass( int iiClassID, boolean ibCheckCompatibility )
	{
		Classes clCurClass, clTemp, clNewClass;	//	clTemp - parent and descedant
		int iParentID, iSaveClassID;
		boolean bCont;	//	, bDebug;
		
		/*
		if ( iiClassID == 62730 )
		{
			bDebug = true;
			System.out.println( "NORWAY" );
		}
		else bDebug = false;
		if ( iiClassID == 84177 )
		{
			System.out.println( "Helping Operations!" );
		}
		if ( iiClassID == 84210 )
		{
			System.out.println( "Helping Actions!" );
			//System.out.println( "Charitable dona!" );
		}
		if ( iiClassID == 84211 )
		{
			System.out.println( "Helping services!" );
		}
		//if ( iiClassID == 84220 )
		if ( iiClassID == 84344 )
		{
			System.out.println( "Communication!" );
		}
		*/
		
		bCont = true;
		iParentID = 0;

		clCurClass = ( Classes ) WDO.htClasses.get( new Integer ( iiClassID ) );
		if  ( clCurClass == null )
		{
			//	give a message	************************************
			return false;
		}

		if ( ibCheckCompatibility )
		{
			if ( htForbiddenClasses.containsKey( new Integer( iiClassID ) ) ) 
			{
				System.out.println( "insertClass - forbidden class (already) " + iiClassID );
				return false;
			}
			//	code is similar to getClassChildren. No wish to unify
			Vector vChildrenClasses = new Vector();
			int iParentOfParameter = clCurClass.getParentID();
			for (int i = 0; i < WDO.vClasses.size(); i++ )
			{
				clTemp = getClassAtPosition( i, "get ClassChildren" );
				
				if ( clTemp != null )
				{
					if ( clTemp.getParentID() == iParentOfParameter )
					{
						vChildrenClasses.add( clTemp );
					}
				}
			}
			clTemp = null;
			boolean bIsIncompatible[ ] = new boolean [vChildrenClasses.size()];
			for( int i = 0; i < bIsIncompatible.length ; i++ ) bIsIncompatible[ i ] = false;
			int iCurClassID;
			boolean bDoIt = true;
			for( int i = 0; i < vChildrenClasses.size(); i++ )
			{
				iCurClassID = ( ( Classes )vChildrenClasses.elementAt( i ) ).getClassID(); 
				for( int j = 0; j < iCompatibleClassesID.length; j++ )
				{
					if ( iCurClassID == iCompatibleClassesID[j])
					{
						//	System.out.println( "Shit happend insertClass!" + iCurClassID );
						j = iCompatibleClassesID.length + 1;	//	stop the loop
						bIsIncompatible[ i ] = true;
						bDoIt = false;
					}
				}
			}
			if ( !bDoIt )
			{
				for( int i = 0; i < vChildrenClasses.size() ; i++ )
				{
					iCurClassID = ( ( Classes )vChildrenClasses.elementAt( i ) ).getClassID(); 
					if (  iCurClassID ==  iiClassID )
					{
						// remove! put into incompatible!
						if ( !bIsIncompatible[i] )
						{
							markClassBranchAsForbidden( iiClassID );
							return false;
						}
						i = vChildrenClasses.size() + 1;
					}
				}
				
			}
			
		}

		clTemp = clCurClass;
		while ( bCont )
		{
			iParentID = clTemp.getParentID();
			if ( iParentID == 0 ) bCont = false;
			else
			{
				clTemp = ( Classes ) WDO.htClasses.get( new Integer ( iParentID ) );
				if ( clTemp == null ) 
				{
					//	2DO to say smthng
					bCont = false;
					iParentID = 0;
				}
				else
				{
					if ( clTemp.getIsInserted() ) bCont = false;
				}
			}
		}
		clNewClass = new Classes( clCurClass.getClassID(), clCurClass.getClassName(), iParentID, clCurClass.getIsLeaf(), clCurClass.getClassDescr(), clCurClass.getStemClassName(), clCurClass.getStemClassDescr(), clCurClass.getBaseOntoID() );
		vResClasses.add( clNewClass );
		htClasses.put( new Integer( clNewClass.getClassID() ), clNewClass );
		
		clCurClass.setIsInserted( true );
		clCurClass.setIsMarked( true );
		
		/*	FALSE! - All the 
		if ( iParentID != 0 ) //	find parent
		{
			for ( int i = 0; i < vResClasses.size(); i++ )
			{
				clTemp = ( Classes ) vResClasses.elementAt( i );
				if ( ( clTemp.getParentID() == iParentID ) && ( clTemp.getClassID() != iiClassID ) )	//	find descedendt of father 
				{
					clTemp.setParentID( iiClassID );
					
				}
			}
			return true;
		}
		
		//	iParentID = 0
		*/
		
		//	find descent or leaves
		vQFrom = null;
		vQFrom = new Vector();
		getClassChildren( iiClassID, 0, 3, ibCheckCompatibility );
		
		//	System.out.println( "InsCl: " + iiClassID + " NoOfCh: " +  vQFrom.size() );
		
		while ( vQFrom.size() > 0 )
		{
			clTemp = ( Classes ) vQFrom.elementAt( 0 );
			vQFrom.removeElementAt( 0 );
			if ( clTemp.getIsInserted() )
			{
				//	Change parentID. In ideal variant the old father should be Thing (0) or ParentID
				//	find class in vResClasses, change father!
				iSaveClassID = clTemp.getClassID();
				for ( int i = 0; i < vResClasses.size(); i++ )
				{
					clTemp = ( Classes ) vResClasses.elementAt( i );
					if ( clTemp.getClassID() == iSaveClassID )	//	find descedendt of father 
					{
						clTemp.setParentID( iiClassID );
						i = vResClasses.size() + 1;	// finish the loop
					}
				}	//	no check if everything OK. It has to be OK
			}
			else
			{
				if ( clTemp.getIsLeaf() )
				{
					//	add the new class and IS-A relation
					clNewClass = new Classes( clTemp.getClassID(), clTemp.getClassName(), iiClassID, true, clTemp.getClassDescr(), clTemp.getStemClassName(), clTemp.getStemClassDescr(), clTemp.getBaseOntoID() );
					vResClasses.add( clNewClass );
					htClasses.put( new Integer( clNewClass.getClassID() ), clNewClass );

					clNewClass = ( Classes ) WDO.htClasses.get( new Integer( clTemp.getClassID() ) );
					if ( clNewClass == null )
					{
						System.out.println( "Class not found: " + "Find InHashTable1, ClassID " + clTemp.getClassID() );
						//	return -1;
					}
					else
					{
						clNewClass.setIsInserted( true );
						clNewClass.setIsMarked( true );
					}
				}
				else getClassChildren( clTemp.getClassID(), 0, 3, ibCheckCompatibility );	//	if not a leaf, has not been inserted
			}
		}
		
		
		return true;
	}

	// the function scans vResClasses (slice), finds each of them in htClasses 
	//	and change value of the flag IsInserted  
	private static void synchClassesInSliceAndOnto( )
	{
		//	System.out.println( "Synchronization started..." );
		
		Classes clTemp;
		Object oClassID;
		for ( int i = 0; i < vResClasses.size(); i++ )
		{
			oClassID = new Integer( ( ( Classes ) vResClasses.elementAt( i ) ).getClassID() );
			clTemp = ( Classes ) WDO.htClasses.get( oClassID );
			if ( clTemp == null ) 
			{
				System.out.println( "Synch - class not found " + oClassID );
			}
			else
			{
				clTemp.setIsInserted( true );
			}
		}
		//	System.out.println( "Synchronization finished" );
		return;
	}
	
	//	iiTypeOfRelation
	//		1 - not inherited
	//		2 - inherited
	//		3 - both
	//	private static void addAssoc( int iiTypeOfRelation )
	private static void addAssoc(  )
	{
		//System.out.println( "Step 5 is under execution..." );

		int iClass1ID, iLoopCount, iParentID;
		Classes clTemp;
		WDAssoc wdaTemp;
		boolean bDoIt;
		
		clTemp = null;
		
		vQTop = null;
		vQTop = new Vector();
		
		iLoopCount = 0;
		
		//	Search for top-level classes
		//	getClassChildrenInSlice( 0, ( -1 ) * iiTypeOfRelation );
		getClassChildrenInSlice( 0, 2 );
		
		while ( vQTop.size() > 0 )
		{
			iLoopCount++;
			clTemp = ( Classes ) vQTop.elementAt( 0 ) ;
			vQTop.removeElementAt( 0 );
			iClass1ID = clTemp.getClassID();
			iParentID = clTemp.getParentID();
			
			if ( !clTemp.getIsAssocProc() )
				/*
			if (
					( iiTypeOfRelation == 1 && !clTemp.getIsAssocProc() )
					|| ( iiTypeOfRelation == 2 && !clTemp.getIsAssocProcInh() )
					|| ( iiTypeOfRelation == 3 && ( !clTemp.getIsAssocProc() || !clTemp.getIsAssocProcInh() ) )
					)
					*/
			{
				for ( int i = 0; i < WDO.vWDAssoc.size(); i++ )	//	search for associative relations
				{
					bDoIt = true;
					
					wdaTemp = ( WDAssoc )WDO.vWDAssoc.elementAt( i );
					
					//	if ( iiTypeOfRelation == 1 && wdaTemp.getIsInherited() ) bDoIt = false;
					//	if ( iiTypeOfRelation == 2 && !wdaTemp.getIsInherited() ) bDoIt = false;
					
					/*
					if ( wdaTemp.getIDFromDB() == 11653 )
					{
						System.out.println( "!!!! FOUND !!!" );
					}
					*/
					
					if ( bDoIt )
					{
						if (
								( 
										( wdaTemp.getClass1ID() == iClass1ID )		//	2007-01-22. Associative relations are not directed 
										|| ( wdaTemp.getClass2ID() == iClass1ID )
								)
								&&
								!htProcessedAssoc.containsKey( new Integer( wdaTemp.getInternalID() ) )
							)
						{
							//	is second class forbidden?
							if (
									( ( wdaTemp.getClass1ID() == iClass1ID ) && htForbiddenClasses.containsKey( new Integer( wdaTemp.getClass2ID() ) ) )
									|| ( ( wdaTemp.getClass2ID() == iClass1ID ) && htForbiddenClasses.containsKey( new Integer( wdaTemp.getClass1ID() ) ) )
								)
							{
									//	System.out.println( "Forbidden class has been found: " + wdaTemp.toFileWithTab() );
							}
							else
							{
								addAssocOne( wdaTemp, iParentID, ( wdaTemp.getClass1ID() == iClass1ID ) );
								htProcessedAssoc.put( new Integer( wdaTemp.getInternalID()), new Integer( 0) );
							}	//	is second class forbidden?
						}
					}	//	DoIt
				}		//	loop by assoc		
			}		//	Associative constraints are not still processed
			
			getClassChildrenInSlice( iClass1ID, 2 );
			//	getClassChildrenInSlice( iClass1ID, ( -1 ) * iiTypeOfRelation );
		}
		System.out.println( "Step 5 has been finished. Total classes: " + iLoopCount );
		
		return;
	}

	private static void addAssocOne( WDAssoc iwdaRel, int iiParentID, boolean ibIsFirstClass )
	{
		int iClass2ID;
		boolean bClass2Found, bIsInherited;
		
		//	2007-01-22
		if ( ibIsFirstClass ) iClass2ID = iwdaRel.getClass2ID();
		else iClass2ID = iwdaRel.getClass1ID();
			
		bClass2Found = htClasses.containsKey( new Integer( iClass2ID ) );  
		bIsInherited =  iwdaRel.getIsInherited();
		
		//	2007-01-23 Begin
		//	check if the second class is from TMO
		if ( ( ( Classes ) WDO.htClasses.get( new Integer( iClass2ID ) ) ).getBaseOntoID() == iBaseOntoIDTMO )
		{
			if ( bDebugAssoc ) System.out.println( "Class is in TMO" + iwdaRel );
			return;
		};
		
		//	2007-01-23 End

		//	Case 1
		if ( !bIsInherited && bClass2Found ) 
		{
			vResAssoc.add( iwdaRel );
			if ( bDebugAssoc ) System.out.println( iwdaRel );		//	2006-06-28	PMNew
			return;
		}

		//	Case 2
		if ( !bIsInherited && !bClass2Found ) 
		{
			//	The same algorith as for hierarchy relations
			if ( insertClass( iClass2ID, true ) )
			{
				vResAssoc.add( iwdaRel );
				if ( bDebugAssoc ) System.out.println( "A: Case 2: Class " + iClass2ID );	//	2006-06-28	PMNew
				if ( bDebugAssoc ) System.out.println( "A: Case 2: Rel " + iwdaRel );		//	2006-06-28	PMNew
			};
			return;
		}
		
		//	Case 3
		if ( bIsInherited && bClass2Found ) 
		{
			//	Check parent of the left class.
			//	The same code as in HIER!
			boolean bFoundAssoc;
			bFoundAssoc = false;
			for ( int i = 0 ; i < vResAssoc.size(); i++ )
			{
				WDAssoc wdaTemp;
				wdaTemp = ( WDAssoc ) vResAssoc.elementAt( i );
				
				//	2007-01-22	
				if (
						( ibIsFirstClass && ( wdaTemp.getClass1ID() == iiParentID  ) && ( wdaTemp.getClass2ID() == iClass2ID ) )
						|| ( !ibIsFirstClass && ( wdaTemp.getClass2ID() == iiParentID  ) && ( wdaTemp.getClass1ID() == iClass2ID ) )
						)
				{
					bFoundAssoc = true;
					i = vResAssoc.size() + 1;
				}
			}
			if ( bFoundAssoc )
			{
				// add as-is
				vResAssoc.add( iwdaRel );
				if ( bDebugAssoc ) System.out.println( "A:Inh&Cl2-AS-IS " + iwdaRel );		//	2006-06-28	PMNew
			}
			else
			{
				// add like first assoc relation
				iwdaRel.setIsNotInherited();
				vResAssoc.add( iwdaRel );
				if ( bDebugAssoc ) System.out.println( "A:Inh&Cl2-NEW " + iwdaRel );		//	2006-06-28	PMNew
			}
			return;
		}

		if ( bIsInherited && !bClass2Found ) 
		{
			//	2do
			if ( bDebugAssoc ) System.out.println( "TVA-WR!!! " + iwdaRel );				//	2006-06-28	PMNew
//			2007-01-22
			if ( ibIsFirstClass ) insertAssocInher( iwdaRel.getClass1ID(), iClass2ID );
			else insertAssocInher( iwdaRel.getClass2ID(), iClass2ID );
		}
		return;
	}

	/**
	 * PAS
	 * @param iiClass1ID - class is in the slice
	 * @param iiClass2ID - class is not in the slice
	 * The algorith,:
	 * 1) search for parent of iiClass2ID in AO. If found - add assoc rel
	 * 2) search for descendor. If found - add assoc rel
	 */
	private static void insertAssocInher( int iiClass1ID, int iiClass2ID )
	{
		Classes clCurClass, clTemp, clNewClass;	//	clTemp - parent and descedant
		int iParentID;
		boolean bCont, bFound;
		
		bCont = true;
		bFound = false;
		iParentID = 0;
		
		clCurClass = ( Classes ) WDO.htClasses.get( new Integer ( iiClass2ID ) );
		if  ( clCurClass == null )
		{
			//	give a message	************************************
			//	return false;
			return;
		}
		
		// search for parent - start
		clTemp = clCurClass;
		while ( bCont )
		{
			iParentID = clTemp.getParentID();
			clTemp = ( Classes ) WDO.htClasses.get( new Integer ( iParentID ) );
			if ( ( iParentID == 0 ) || ( clTemp == null ) ) bCont = false;
			else
			{
				if ( clTemp.getIsInserted() ) 
				{
					bCont = false;
					bFound = true;
				}
			}
		}
		//	search for parent - end

		if ( !bFound )	//	iParentID == 0 ) //	search for descender
		{
			vQFrom = null;
			vQFrom = new Vector();
			getClassChildren( iiClass2ID, 0, 3, true );
			bCont = true;
			while ( ( vQFrom.size() > 0 )&& bCont )
			{
				clTemp = ( Classes ) vQFrom.elementAt( 0 );
				vQFrom.removeElementAt( 0 );
				iParentID = clTemp.getClassID();
				if ( clTemp.getIsInserted() ) 
				{
					bCont = false;
					bFound = true;
				}
				else getClassChildren( clTemp.getClassID(), 0, 3, true );
			}
		}

		//	2007-01-22	!!! Should be changed. !!! wdaTemp = new WDAssoc( ... )
		//	ibIsFirst should be taken into account!
		//	Now it does not matter... but in the future...
		
		if ( bFound )	//	( iParentID != 0 ) //	parent has been found 
		{
			WDAssoc wdaTemp;
			wdaTemp = new WDAssoc( iiClass1ID, iParentID, false, iiClass1ID, -1, iCountAssoc-- );	//	No ID!
			vResAssoc.add( wdaTemp );
			if ( bDebugAssoc ) System.out.println( "Added new relation: " + wdaTemp );		//	2006-06-28	PMNew
			// DELETE REFERENCES TO THE ID TO SPEED-UP THE PROCESS. At the moment - no sence
			return;
		}
		
		if ( insertClass( iiClass2ID, true ) )
		{
			WDAssoc wdaTemp;
			wdaTemp = new WDAssoc( iiClass1ID, iiClass2ID, false, iiClass1ID, -1, iCountAssoc-- );	//	No ID!
			vResAssoc.add( wdaTemp );
			if ( bDebugAssoc ) System.out.println( "Added new class: " + wdaTemp );			//	2006-06-28	PMNew					
			return;
		};
		
	}	//	insertAssocInher

	private static void addAttrs()		//	Step Last
	{
		//	ATT! QFrom is used in sub-procedure!!!
		System.out.println( "Step Last is starting..." );

		int iClassID, iLoopCount, iParentID, iAttrID;
		Classes clTemp;
		Attributes attrTemp;
		ClassAttr caTemp, caTempSlice;
		boolean bFound;
		
		clTemp = null;
		
		vQTop = null;
		vQTop = new Vector();
		
		iLoopCount = 0;
		
		//	Search for top-level classes
		getClassChildrenInSlice( 0, 3 );
		System.out.println( "Getting pairs..." );
		while ( vQTop.size() > 0 )
		{
			iLoopCount++;
			clTemp = ( Classes ) vQTop.elementAt( 0 ) ;
			vQTop.removeElementAt( 0 );
			iClassID = clTemp.getClassID();
			iParentID = clTemp.getParentID();
			for ( int i = 0; i < WDO.vClassAttr.size(); i++ )	//	search for attributes
			{
				caTemp = ( ClassAttr )WDO.vClassAttr.elementAt( i );
				if ( caTemp.getClassID() == iClassID )
				{
					//	Check if it is inherited
					//	Not inherited - add relation, add attribute
					if ( !caTemp.getIsInherited() ) vResClassAttr.add( caTemp );
					else
					{
						//	Find attribute in parent's class
						iAttrID = caTemp.getAttrID();
						bFound = false;
						for ( int j = 0; j < vResClassAttr.size(); j++ )
						{
							caTempSlice = ( ClassAttr )vResClassAttr.elementAt( j );
							if ( ( caTempSlice.getClassID() == iParentID ) && ( caTempSlice.getAttrID() == iAttrID ) )
							{
								bFound = true;
								j = vResClassAttr.size() + 1;
							}
						}
						if ( bFound )
						{
							vResClassAttr.add( caTemp );
						}
						else
						{
							vResClassAttr.add( new ClassAttr( iClassID, iAttrID, false, iClassID) );
						}
					}	//	Inherited
				}		//	Class is equal
			}			//	Loop by pairs of classes and attributes
			getClassChildrenInSlice( iClassID, 3 );
		}	//	endwhile
		
		System.out.println( "Getting attributes..." );
		for ( int j = 0; j < vResClassAttr.size(); j++ )
		{
			caTempSlice = ( ClassAttr )vResClassAttr.elementAt( j );
			if ( !caTempSlice.getIsInherited() )
			{
				iAttrID = caTempSlice.getAttrID();
				attrTemp = ( Attributes ) WDO.htAttributes.get( new Integer( iAttrID ) );
				if ( attrTemp != null )
				{
					vResAttr.add( attrTemp );
					//	HASH TABLE
				}
			}
		}
		
		System.out.println( "Step Last has been finished. Total attributes: " + vResAttr.size() );
	}
	
	private static void addFunc()		//	Step Last
	{
		Classes clTemp, clMethod;
		int iClass1ID, iParentID, iMethodID, iMethodParentID;
		WDFunc wdfTemp;
		Vector vDelClasses, vDelFunc;
		
		iClass1ID = 0;
		iParentID = 0;
		iMethodID = 0;
		iMethodParentID = 0;
		
		clTemp = null; 
		clMethod = null;
		
		vDelClasses = new Vector();
		vDelFunc = new Vector();
		
		vQTop = null;
		vQTop = new Vector();
		
		//	Search for top-level classes
		getClassChildrenInSlice( 0, 1 );
		
		while ( vQTop.size() > 0 )
		{
			clTemp = ( Classes ) vQTop.elementAt( 0 ) ;
			vQTop.removeElementAt( 0 );
			iClass1ID = clTemp.getClassID();
			iParentID = clTemp.getParentID();
			
			for ( int i = 0; i < WDO.vWDFunc.size(); i++ )	//	search for functional relations
			{
				wdfTemp = ( WDFunc )WDO.vWDFunc.elementAt( i );
				if ( ( wdfTemp.getRelationType() == 0 ) && ( wdfTemp.getRelationID() == iClass1ID ) )
				{
					//	addPartOf( wdfTemp, iParentID );
					//	Check if method is already added. If not - add it
					iMethodID = wdfTemp.getFuncValue();
					boolean bDoIt = true;
					if ( htClasses.containsKey( new Integer( iMethodID ) ) )
					{
						bDoIt = false;
						vResFunc.add( wdfTemp );
					};
					if ( bDoIt )
					{
						for ( int j = 0; j < vDelClasses.size(); j++ )
						{
							if ( ( ( Classes )vDelClasses.elementAt( j ) ).getClassID() == iMethodID )
							{
								vDelFunc.add( wdfTemp );
								bDoIt = false;
							}
						}	//	check for delayed classes
					}
					if ( bDoIt )
					{
						clMethod = ( Classes )WDO.htClasses.get( new Integer( iMethodID ) );
						if ( clMethod == null )
						{
							bDoIt = false;
							System.out.println( "Can not find method " + iMethodID );
						}
						else iMethodParentID = clMethod.getParentID(); 
					}	//	find method
					if ( bDoIt )	//	is it subclass?
					{
						if ( iMethodParentID != WDO.iThingID )
						{
							if ( !htClasses.containsKey( new Integer( iMethodParentID ) ) )
							{
								vDelFunc.add( wdfTemp );
								vDelClasses.add( clMethod );
								bDoIt = false;
							}	//	put into delayed
							else
							{
//								!!! Put information about parent
								clMethod.setPositionOfParent( findClassPosition( clMethod.getParentID() ) );
								vAltFunc.add( wdfTemp );
								vAltClasses.add( clMethod );
								htClasses.put( new Integer( iMethodID ), clMethod );
								bDoIt = false;
								System.out.println( "Added class to the alternative list: " + iMethodID );
							}
						}
					}	//	parent != Thing
					if ( bDoIt )	//	This is not a subclass
					{
						vResFunc.add( wdfTemp );
						vResClasses.add( clMethod );
						htClasses.put( new Integer( iMethodID ), clMethod );
						bDoIt = false;
						//	System.out.println( "Added class to the main list: " + iMethodID );
					}
					
				}	//	Functional constraint on attribute
			}		//	loop by functional constraints
			
			getClassChildrenInSlice( iClass1ID, 1 );
		}	// traverse of slice
		System.out.println( "Delayed classes: " + vDelClasses.size() );
		System.out.println( "Delayed constraints: " + vDelFunc.size() );
		for ( int j = 0; j < vDelClasses.size(); j++ )
		{
			//	search for parent. If it is in the list - add it to alternative. Else - add it to main. remove from list, remove constraints
			clMethod = ( Classes )vDelClasses.elementAt( j );
			iMethodID = clTemp.getClassID(); 
			iMethodParentID = clTemp.getParentID();
			boolean bToMain = false;
			if ( htClasses.containsKey( new Integer( iMethodParentID ) ) )
			{	//	add to alternative list
				clMethod.setPositionOfParent( findClassPosition( clMethod.getParentID() ) );
				clMethod.setPositionOfParent( 0 );
				vAltClasses.add( clMethod );
				htClasses.put( new Integer( iMethodID ), clMethod );
			}
			else
			{	//	add to main list
				clMethod.setParentID( WDO.iThingID );
				vResClasses.add( clMethod );
				htClasses.put( new Integer( iMethodID ), clMethod );
				bToMain = true;
			}
			for ( int k = 0; k < vDelFunc.size(); k++ )
			{
				wdfTemp = ( WDFunc )vDelFunc.elementAt( k );
				if ( wdfTemp.getFuncValue() == iMethodID )
				{
					if ( bToMain ) vResFunc.add( wdfTemp );
					else vAltFunc.add( wdfTemp );
				}
			}
		}
		//	System.out.println( "Thing ID: " + WDO.iThingID );
	}	//	addFunc()
	
	private static boolean isClassesLeft()		//	Step Last
	{
		//	System.out.println( "LOOP for Hierarchy and Associative relations" );
		for (int i = 0; i< vResClasses.size(); i++ )
		{
			if ( 
					( !( ( Classes )vResClasses.elementAt( i ) ).getIsAssocProc() ) 
					|| ( !( ( Classes )vResClasses.elementAt( i ) ).getIsHierProc() )	// 2007-01-16 - was a bug with getIsAssocProc() - it was twice 
				) 
			{
				System.out.println( "i: " + i + " Class: " + ( Classes )vResClasses.elementAt( i ) );
				//	if ( i != 197 )
				return true;
			};
		}
		return false;
	}
	
	private static void saveSliceToFile()
	{
		String sFileName = "C:\\a.txt";
		try
		{
			FileWriter frHandle = new FileWriter( sFileName );
			BufferedWriter brBuffer = new BufferedWriter( frHandle );
			
			/*
			for ( int i = 0; i < WDO.vClassAttr.size(); i++ )
			{
				brBuffer.write( WDO.vClassAttr.elementAt( i ).toString() + "\r"  );
			};
			*/
			for ( int i = 0; i < vResClasses.size(); i++ )
			{
				//	brBuffer.write( ( ( Classes ) vResClasses.elementAt( i ) ).toFile() + "\r"  );
				brBuffer.write( ( ( Classes ) vResClasses.elementAt( i ) ).toFileWithTab() + "\r"  );
			};
			brBuffer.write( "EndOfClasses" + "\r"  );

			brBuffer.write( "Attributes:\r"  );
			for ( int i = 0; i < vResAttr.size(); i++ )
			{
				//	brBuffer.write( ( ( Attributes )vResAttr.elementAt( i ) ).toFile() + "\r"  );
				brBuffer.write( ( ( Attributes )vResAttr.elementAt( i ) ).toFileWithTab() + "\r"  );
			};
			brBuffer.write( "EndOfAttributes" + "\r"  );
			
			brBuffer.write( "ClassesAttributes:\r"  );
			for ( int i = 0; i < vResClassAttr.size(); i++ )
			{
				//	brBuffer.write( vResClassAttr.elementAt( i ).toString() + "\r"  );
				brBuffer.write( ( ( ClassAttr )vResClassAttr.elementAt( i ) ).toFileWithTab() + "\r"  );
			};
			brBuffer.write( "EndOfClassAttributes" + "\r"  );

			brBuffer.write( "Associative:\r"  );
			for ( int i = 0; i < vResAssoc.size(); i++ )
			{
				brBuffer.write( ( ( WDAssoc )vResAssoc.elementAt( i ) ).toFileWithTab() + "\r"  );
			};
			brBuffer.write( "EndOfAssociative" + "\r"  );

			brBuffer.write( "Hierarchical:\r"  );
			for ( int i = 0; i < vResHier.size(); i++ )
			{
				brBuffer.write( ( ( WDHier )vResHier.elementAt( i ) ).toFileWithTab() + "\r"  );
			};
			brBuffer.write( "EndOfHierarchical" + "\r"  );

		    brBuffer.close();
		    frHandle.close();
		}
		catch ( Exception e ) 
		{
		    // e.printStackTrace( );
			System.out.println( "Can not open file" ); 
		}
		/*
		if ( vResAttr.size() > 0 ) System.out.println( "\nATTRIBUTES:" );
		for ( int i = 0; i < vResAttr.size(); i ++ )
		{
			System.out.println( ( Attributes ) vResAttr.elementAt( i ) );
		};
		*/

	}
	
	/**
	 * Print auxiliary information about slice
	 * @param sTitle
	 */
	private static void printIntermediateData( String sTitle )
	{
		System.out.println( "=============== " + sTitle + " ===============BEGIN" );
		if ( ( vResClasses.size() == 0 ) && ( vResAttr.size() == 0 ) )
		{
			System.out.println( "The slice is empty." );
		}
		else
		{
			if ( vResClasses.size() > 0 ) System.out.println( "CLASSES:" ); 
			for ( int i = 0; i < vResClasses.size(); i ++ )
			{
				//	System.out.println( "" + ( i + 1 ) + " " + ( Classes ) vResClasses.elementAt( i ) );
				System.out.println( ( ( Classes ) vResClasses.elementAt( i ) ).toFileWithTab() );
			};
			
			int iCountAssoc, iCountAssocInher;
			iCountAssoc = vResAssoc.size();
			iCountAssocInher = 0;
			if ( iCountAssoc > 0 )System.out.println( "ASSOCIATIVE:" );
			for ( int ii = 0; ii < iCountAssoc; ii++ )
			{
				if ( ( ( WDAssoc ) vResAssoc.elementAt( ii ) ).getIsInherited() ) iCountAssocInher++;
				System.out.println( ( ( WDAssoc ) vResAssoc.elementAt( ii ) ).toFileWithTab() );
			}
			
			System.out.println( "\nFOUND ASSOCIATIVE RELATIONS (In ontology//Added//Inherited). " + WDO.vWDAssoc.size() + "//"+ 
					iCountAssoc + "//" + iCountAssocInher );
			
			int iCountHier, iCountHierInher;
			iCountHier = vResHier.size();
			iCountHierInher = 0;
			if ( iCountAssoc > 0 )System.out.println( "HIERARCHY:" );
			for ( int ii = 0; ii < iCountHier; ii++ )
			{
				if ( ( ( WDHier ) vResHier.elementAt( ii ) ).getIsInherited() ) iCountHierInher++;
				System.out.println( ( ( WDHier ) vResHier.elementAt( ii ) ).toFileWithTab() );
			}
			
			System.out.println( "\nFOUND HIERARCHICAL RELATIONS (In ontology//Added//Inherited). " + WDO.vWDHier.size() + "//"+ 
					iCountHier + "//" + iCountHierInher );

			if ( vAltClasses.size() > 0 ) System.out.println( "Alteernative classes:" ); 
			for ( int i = 0; i < vAltClasses.size(); i ++ )
			{
				System.out.println( ( ( Classes ) vAltClasses.elementAt( i ) ).toFileWithTab() );
			};
			for ( int i = 0; i < vAltFunc.size(); i ++ )
			{
				System.out.println( ( ( WDFunc ) vAltFunc.elementAt( i ) ).toString() );
			};

		}	//	print the result
		System.out.println( "=============== " + sTitle + " ===============END" );
		
	}	//	PrintIntermediateData
	
	private static int calcQuantOfAttrs( int iiClassID )
	{
		ClassAttr clattrTemp;
		int iTempClassID, iQuantOfAttrs = 0;
		
		
		for ( int i = 0; i < WDO.vClassAttr.size(); i++ )
		{
			clattrTemp = ( ClassAttr )WDO.vClassAttr.elementAt( i );
			iTempClassID = clattrTemp.getClassID();
			if ( iTempClassID == iiClassID ) iQuantOfAttrs++;
		};
		
		return iQuantOfAttrs;
	}
	
	private static void markClassBranchAsForbidden( int iiClassID )
	{
		//	traverse the tree
		Classes clTemp;
		
		clTemp = null;
		
		vQComp = null;
		vQComp = new Vector();
		
		//	Search for top-level classes
		addIDToForbiddenTable( iiClassID );
		getClassChildren( iiClassID, -1, 4, false );		//!4
		
		while ( vQComp.size() > 0 )
		{
			clTemp = null;
			clTemp = ( Classes )vQComp.elementAt( 0 );
			addIDToForbiddenTable( clTemp.getClassID() );
			getClassChildren( clTemp.getClassID(), -1, 4, false );
			vQComp.removeElementAt( 0 );
		}
	}
	private static void addIDToForbiddenTable( int iiClassID )
	{
		if ( !htForbiddenClasses.containsKey( new Integer( iiClassID ) ) )
		{
			htForbiddenClasses.put( new Integer( iiClassID ), new Integer( iiClassID ));
		}
	}

	private static int findClassPosition( int iiClassID )
	{
		for ( int i = 0; i < vResClasses.size(); i++ )
		{
			if ( ( (Classes )vResClasses.elementAt( i ) ).getClassID() == iiClassID ) return i;
		}
		return -1;
	}
}
